<?php
/**
 * @link https://www.kancloud.cn/cleverstone/ymb2
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\helper;

use Yii;
use DateTime;
use DateInterval;
use DateTimeZone;
use yii\base\ErrorException;

/**
 * 日期和时间
 * @author clevstn
 * @since ym2.0
 */
class T
{
    /**
     * 当前时间/日期
     * @param bool|string $toString
     * - bool   是否转字符串，是：Y-m-d H:i:s 否：当前时间戳
     * - string 格式化字符，如：Y.m.d
     *
     * @param string $timeZone 时区，默认跟随框架
     * @return int|string
     * @throws \Exception
     */
    public static function now($toString = true, $timeZone = '')
    {
        $datetime = new DateTime('now', self::timeZone($timeZone));

        if ($toString === true) {
            return $datetime->format('Y-m-d H:i:s');
        } elseif (is_string($toString)) {
            return $datetime->format($toString);
        } else {
            return $datetime->getTimestamp();
        }
    }

    /**
     * 日期区间分割成数组。
     * @param string|null $rangDateStr 日期区间字符串，如：2020.02.12/2020.05.13
     * @param string $splitChar 字符串分隔符，如：/
     * @param boolean $intoTime 是否转换为时间戳
     * @return array|null[]
     * @throws ErrorException
     */
    public static function rangeDateSplit($rangDateStr, $splitChar = '/', $intoTime = false)
    {
        if (empty($rangDateStr)) {
            return $intoTime ? [0, 0] : [null, null];
        }

        return array_map(function ($value) use ($intoTime) {
            $value = trim($value);
            if (!$intoTime) {
                return $value;
            }

            $result = strtotime($value);
            if (false === $result) {
                throw new ErrorException('The datetime is illegal. ');
            }

            return $result;
        }, explode($splitChar, $rangDateStr));
    }

    /**
     * 自然语言转日期区间
     * ```php
     * T::createRangeDate('-3 days');
     * // 输出：'2025-08-30 00:00:00 / 2025-08-32 23:59:59'
     * ```
     * @param string $startStr 自然语言描述开始日期
     * @param string $endStr 自然语言描述结束日期
     * @param string $startFormat 开始日期PHP格式
     * @param string $endFormat 结束日期PHP格式
     * @param string $separator 区间分割符
     * @return string
     */
    public static function createRangeDate(string $startStr, string $endStr = 'now', string $startFormat = 'Y-m-d 00:00:00', string $endFormat = 'Y-m-d 23:59:59', string $separator = '/'): string
    {
        return date($startFormat, strtotime($startStr)) . " $separator " . date($endFormat, strtotime($endStr));
    }

    /**
     * Calculate total number of days between the two dates.
     *
     * @param string $d1 the date
     * @param string $d2 other date
     * @param boolean $resultIncludeFirstDay 结果是否包含第一天。
     * @return int
     * @throws \Exception
     */
    public static function spansDays($d1, $d2, $resultIncludeFirstDay = true)
    {
        $timeZone = self::timeZone();
        $dt1 = new DateTime($d1, $timeZone);
        $dt2 = new DateTime($d2, $timeZone);
        $di = $dt1->diff($dt2);

        return $resultIncludeFirstDay ? ($di->days + 1) : $di->days;
    }

    /**
     * 相对天数转绝对时间
     * @param int $days 天数
     * @param boolean $resultToTimestamp 结果是否转时间戳
     * @param boolean $formatTime 是否格式化时间，如: 一个月前 static::dayToAbsoluteDate(-30, false, true); //2024-09-07 00:00:00 (当前日期2024-10-06 17:14:00)
     * @return int|string
     */
    public static function dayToAbsoluteDate($days, $resultToTimestamp = true, $formatTime = false)
    {
        $datetime = new DateTime($formatTime ? date('Y-m-d 24:00:00') : 'now', self::timeZone());
        $method = $days < 0 ? 'sub' : 'add';
        $interval = new DateInterval('P' . abs($days) . 'D');
        $datetime->{$method}($interval);

        return $resultToTimestamp ? $datetime->getTimestamp() : $datetime->format('Y-m-d H:i:s');
    }

    /**
     * @param string|null $timeZone 时区字符串，如：PRC/UTC/Asia/Shanghai
     * @return DateTimeZone
     * @throws \Exception
     */
    protected static function timeZone($timeZone = null)
    {
        return new DateTimeZone($timeZone ?: Yii::$app->timeZone);
    }
}